﻿using System;
using System.IO;

#if !RootNamespace
namespace OmniKits.Extensions
{
#endif
    public static class StreamEx
    {
        public static int DefaultBufferSize { get; set; } = 81920;
        public const int MinimumBufferSize = 4096;

        public static int EatAll(this Stream source, int bufferSize, bool close = false)
        {
            if (bufferSize < MinimumBufferSize)
                bufferSize = MinimumBufferSize;

            var count = 0;
            int read;
            var buffer = new byte[bufferSize];
            try
            {
                while ((read = source.Read(buffer, 0, bufferSize)) > 0)
                    count += read;
                return count;
            }
            finally
            {
                if (close) source.Close();
            }
        }
        public static int EatAll(this Stream source, bool close = false)
            => source.EatAll(DefaultBufferSize, close);

        public static long FeedTo(this Stream source, Stream target, int bufferSize, bool closeSource, bool closeTarget)
        {
            if (bufferSize < MinimumBufferSize)
                bufferSize = MinimumBufferSize;

            long count = 0;
            int read;
            var buffer = new byte[bufferSize];
            try
            {
                while ((read = source.Read(buffer, 0, bufferSize)) > 0)
                {
                    target.Write(buffer, 0, read);
                    count += read;
                }
                return count;
            }
            finally
            {
                if (closeSource) source.Close();
                if (closeTarget) target.Close();
            }
        }
        public static long FeedTo(this Stream source, Stream target, int bufferSize, bool close = false)
            => source.FeedTo(target, bufferSize, close, close);
        public static long FeedTo(this Stream source, Stream target, bool closeSource, bool closeTarget)
            => source.FeedTo(target, DefaultBufferSize, closeSource, closeTarget);
        public static long FeedTo(this Stream source, Stream target, bool close = false)
            => source.FeedTo(target, DefaultBufferSize, close, close);

        public static int ReadBlock(this Stream source, byte[] buffer, int offset, int count)
        {
            var len = buffer.Length;
            if (offset < 0 || offset > len)
                throw new ArgumentException(null, nameof(offset));
            if (count < 0 || count > len)
                throw new ArgumentException(null, nameof(count));
            if (count == 0)
                return 0;
            if (offset + count > len)
                throw new ArgumentException();

            var read = 0;
            do
            {
                var a = source.Read(buffer, offset + read, count - read);
                if (a == 0)
                    break;

                read += a;
            } while (read < count);

            return read;
        }
    }
#if !RootNamespace
}
#endif
